
import java.util.*;

/**
 * Datapath es una clase que manejan las operaciones de cada una de las etapas
 * de ejecución.
 *
 * @author Villalva Bueno Arely Eunice
 * @author Romero Rodriguez Gabriel Eduardo
 */
public class Datapath {

    public static Fetch myFetch;
    public static Decode myDecode;
    public static Execute myExecute;
    public static Memory myMemory;
    public static WriteBack myWriteBack;
    public static MemoryType mainMemory;
    public static MemoryType regFile;
    public static ListBoxes lb;
    public static Vector Instructions;
    public static Stages stg;

    /**
     * Crea un Datapath objeto e incializa cada uno de sus componentes
     *
     * @see Instruction
     * @see ListBoxes
     * @see Stages
     */
    public Datapath(Vector _Instructions,
            ListBoxes _lb,
            Stages _stg) {
        Instructions = _Instructions;
        lb = _lb;
        stg = _stg;
        mainMemory = new MemoryType();
        regFile = new MemoryType();
        myFetch = new Fetch();
        myDecode = new Decode();
        myExecute = new Execute();
        myMemory = new Memory();
        myWriteBack = new WriteBack();
    }

    /**
     * Maneja un ciclo de la ejecución del programa.
     * 
     */
    public boolean step() {

        boolean allNOPs = false;
        myWriteBack.myInstruction = myMemory.myInstruction;
        myMemory.myInstruction = myExecute.myInstruction;
        myExecute.myInstruction = myDecode.myInstruction;
        myDecode.myInstruction = myFetch.myInstruction;
        myWriteBack.PC = myMemory.PC;
        myMemory.PC = myExecute.PC;
        myExecute.PC = myDecode.PC;
        if (myDecode.isStall == false) {
            myDecode.PC = myFetch.PC;
        }

        // carga la siguiente instrucción
        myFetch.step(Instructions, myDecode);
        myDecode.step(Instructions, regFile, myMemory,
                myWriteBack, myFetch, myExecute, lb);
        myExecute.step(Instructions, myFetch, myDecode, lb);
        myMemory.step(mainMemory, lb);
        allNOPs = (myFetch.myInstruction.opcode == 0) &&
                (myDecode.myInstruction.opcode == 0) &&
                (myExecute.myInstruction.opcode == 0) &&
                (myMemory.myInstruction.opcode == 0);
        myWriteBack.step(regFile, Instructions, lb, allNOPs);

        // muestra el estado de las etapas
        stg.clearAll();
        stg.fetch.setText(myFetch.toString());
        stg.decode.setText(myDecode.toString());
        stg.execute.setText(myExecute.toString());
        stg.memory.setText(myMemory.toString());
        stg.wb.setText(myWriteBack.toString());

        return myWriteBack.programaHecho();
    }

    /**
     * Fija el estado.
     */
    public void enableForwarding(boolean cond) {
        myDecode.forwarding = cond;
    }

    /**
     * Fija el estado de la predicción.
     */
    public void enableBP(boolean cond) {
        myDecode.branchPrediction = cond;
    }
}
